﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace app
{
    static class Peers
    {
        static List<Peer> peers = new List<Peer>();

        internal static void Start()
        {
            Thread thread = new Thread(new ThreadStart(RefreshPeers));

            thread.Start();
        }

        static void RefreshPeers()
        {
            if (peers.Count == 0)
            {
                LoadPeersFromFile();
            }

            if (peers.Count < Parameters.maxConnections)
            {

            }
        }
       
        internal static void Send(byte[] address, byte[] data = null)
        {
            Peer[] pp = Peers.GetPeers(address);

            //pp = pp.OrderBy(x => x.Stats.distance).ToArray();

            foreach (Peer p in pp)
                Request.Send(p, address: address, data: data);
        }

        internal static void LoadPeersFromFile()
        {
            byte[] pp = new byte[0];

            if (File.Exists("peers.txt"))
                pp = File.ReadAllBytes("peers.txt");

            int reg_size = Parameters.addressSize + 8 + 10;

            Peer[] peers = new Peer[pp.Length / reg_size];

            for (int i = 0; i < pp.Length / reg_size; i++)
            {
                peers[i] = new Peer(pp.Skip(i * (reg_size)).Take(reg_size).ToArray());
            }

            Peers.peers.Clear();

            Peers.peers.AddRange(peers);
        }

        internal static Peer[] GetPeers(byte[] address = null, byte[] originAddress = null, IPEndPoint originEndPoint = null)
        {
            if (address == null)
            {
                Random r = new Random();

                return peers.
                    Where(x => 
                        (originAddress == null || Addresses.Compare(x.Address, originAddress) != 0)
                        && (originEndPoint == null || x.IPEndPoint.GetHashCode() != originEndPoint.GetHashCode() )).
                    OrderBy(x => r.Next()).Take(Parameters.propagation).ToArray();
            }

            return peers.
                Where(x => originAddress == null || Addresses.Compare(x.Address, originAddress) != 0).
                OrderBy(x => Addresses.Compare(x.Address, address)).Take(Parameters.propagation).
                ToArray();
        }

        internal static void GetPeer(string base64EndPoint)
        {
            byte[] b  = Convert.FromBase64String(base64EndPoint);

            IPEndPoint p = new IPEndPoint(
                new IPAddress(b.Take(Parameters.ipv4Addresssize).ToArray()),
                BitConverter.ToUInt16(b, Parameters.ipv4Addresssize));

            Request.Send(p, command: RequestCommand.GetPeer);
        }

        internal static void AddRange(byte[] request)
        {
            int reg_size = Parameters.addressSize + Parameters.ipv4Addresssize + sizeof(Int16); 

            int c = request.Length / reg_size;

            Peer p;

            for(int i = 0; i < c; i++)
            {
                p = new Peer(request.Skip(reg_size * i).Take(reg_size).ToArray());

                if (peers.Any(x => Addresses.Compare(x.Address, p.Address) == 0))
                {
                    Log.Add("Old Peer", p, new byte[0]);
                }
                else if(Addresses.Compare(p.Address, Program.localPeer.Address) == 0)
                {
                    Log.Add("Same Peer", p, new byte[0]);
                }
                else
                {
                    peers.Add(p);

                    Log.Add("New Peer", p, new byte[0]);
                }
            }
        }
    }

    //command
    //    HttpGet = 542393671
    // case Command.HttpGet:
    //{
    //    string str = "HTTP/1.x 200 OK\r\n";
    //    str += "Content-Disposition: attachment; filename=windows.zip\r\n";
    //    str += "Content-Type: application/octet-stream\r\n";
    //    str += "Content-Length: 39450\r\n\r\n";

    //    byte[] bb = System.Text.Encoding.ASCII.GetBytes(str);

    //    state.socket.BeginSend(bb, 0, bb.Length, 0, new AsyncCallback(OnHttp), state);

    //    return;

    //}
}